/*
 * tp boole
 */
package boole.utils;

import boole.circuit.*;
import boole.port._PortEntree;
import boole.port._PortSortie;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;

/**
 *
 * @author Rémi PIOTAIX <remi.piotaix@gmail.com>
 * @author Morgan Bidois
 * @author Thomas Nds nds.thomas@gmail.com
 * @author Xu
 */
public class ParcoursTopologique {

    private LinkedList<_Operable> composants = new LinkedList<>();
    private HashSet<_Operable> vus = new HashSet<>();

    /**
     * parcour à partir du générateur passé en paramètre.
     *
     * @param po
     */
    public ParcoursTopologique(Generateur po) {
        this.parcours(po);
    }

    /**
     * parcours topologique du circuit en fonction de ses dépendances.
     * @param c le circuit à trier.
     *
     */
    public ParcoursTopologique(Circuit c) {
        this.parcoursCircuit(c);
    }

    /**
     * Parcours topologique a partir d'un composant
     * @ensure la lsite chainée composants est triée.
     * @param composant
     */
    private void parcours(_PortOwner composant) {
        if (this.vus.contains(composant)) {
            System.out.println("Parcours de " + composant + " DEJA VU");
            return;
        }

        System.out.println("Parcours de " + composant);

        vus.add(composant);// ajout aux gris
        for (int i = 1; i <= composant.getNombreSorties(); i++) {
            _PortSortie ps = composant.getSortie(i);
            for (_PortEntree pe : ps.getPortsEntree()) {
                this.parcours(pe.getOwner());
            }
        }
        composants.addFirst(composant);// ajout aux noirs
    }

    /**
     * Lance la parcours d'un circuit cad:
     *
     * @param circuit
     */
    private void parcoursCircuit(Circuit circuit) {
        //si deja passé, on s'arrète
        if (this.vus.contains(circuit)) {
            System.out.println("ParcoursCircuit de " + circuit + " DEJA VU");
            return;
        }
        System.out.println("ParcoursCircuit de " + circuit);

        this.vus.add(circuit);

        // si il possède des d'entrées, on propage à partir d'eux
        if (circuit instanceof _PortOwner) {
            System.out.println("Le circuit " + circuit + " a des entrées");
            CircuitOuvert co = (CircuitOuvert) circuit;
            for (int n = 1; n <= co.getNombreEntrees(); n++) {
                Set<_PortEntree> spe = co.getEntree(n).getPortsEntree();
                for (_PortEntree pe : spe) {
                    _PortOwner po = pe.getOwner();
                    this.parcours(po);
                }
            }
        }
        // puis à partir des générateurs
        for (_Composant composant : circuit.getOperateurs().values()) {
            if (composant instanceof Generateur || (composant instanceof _PortOwner && ((_PortOwner) composant).getNombreEntrees() == 0)) {
                this.parcours(composant);
            }
        }
    }

    /**
     * parcourir la liste et calculer
     * @ensure le circuit est calculé.
     * @param c
     */
    public void traitement() {
        System.out.println("traitement");
        Iterator<_Operable> i = composants.iterator();
        while (i.hasNext()) {
            i.next().calcul();
        }
    }
}
